筆記目錄

Skip to content

如何在 Docker 使用 GitLab CI

TLDR

  • 使用 Docker Compose 部署 GitLab 時,務必設定 external_url 以確保 SSH 與 HTTP 連結正確。
  • 若需使用 artifacts 功能,請務必使用 Docker Volume 而非 Bind Mount,以避免權限不足問題。
  • GitLab Runner 若使用 Docker Executor,需掛載 /var/run/docker.sock 以便在容器內呼叫外部 Docker Engine。
  • 註冊 Runner 時,若 GitLab 未設定正確的 external_url,需在 config.toml 中手動指定 clone_url
  • .gitlab-ci.yml 中的 network_mode 不可設為 host,建議使用 gitlab_default 以避免網路衝突。
  • 部署階段若需操作 Docker,建議透過掛載 docker.sock 的方式(Docker-outside-of-Docker),而非使用 DIND。

在 Docker 上安裝 GitLab

在 Docker 環境中部署 GitLab 時,建議使用 Docker Compose 進行管理。

yaml
version: '3.7'

services:
  GitLab-Server:
    image: 'gitlab/gitlab-ee:latest'
    container_name: GitLab-Server
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://127.0.0.1:5080/'
        nginx['listen_port'] = 80
        gitlab_rails['gitlab_shell_ssh_port'] = 5022
    ports:
      - 5080:80
      - 5443:443
      - '5022:22'
    privileged: true
    volumes:
      - .\Volumes\GitLab-Server\Config:/etc/gitlab
      - data:/var/opt/gitlab
      - .\Volumes\GitLab-Server\Logs:/var/log/gitlab
    shm_size: '256m'
    networks:
      default:
        ipv4_address: 172.20.0.2
    restart: always
volumes:
  data:
networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1

TIP

  • external_url 必須設定,否則儲存庫的 SSH 與 HTTP 連結網址會出現異常。
  • 若使用非 80 port,需同時設定 nginx['listen_port']
  • 若出現「invalid port specification」錯誤,請將 ports 設定中的 5022:22 改為字串格式(加上引號)。
  • /var/opt/gitlab 建議使用 Volume 連結,若使用 Bind Mount 可能會導致 artifacts 功能因權限不足而失效。

在 Docker 上安裝與註冊 GitLab Runner

若要執行 CI/CD 任務,需額外部署 GitLab Runner。若使用 Docker Executor,必須掛載 Docker Socket。

yaml
  GitLab-Runner:
    image: gitlab/gitlab-runner:latest
    container_name: GitLab-Runner
    privileged: true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - .\Volumes\GitLab-Runner\Config:/etc/gitlab-runner
    networks:
      default:
        ipv4_address: 172.20.0.3
    restart: always

註冊流程

執行指令:docker exec -it GitLab-Runner gitlab-runner register

  • 什麼情況下會遇到問題:當 GitLab 未設定 external_url 或使用 127.0.0.1 時,Runner 可能無法正確連線。
  • 解決方案:在 config.toml 中手動加入 clone_url = "http://172.20.0.2"
  • 設定重點:在 config.toml 中,將 privileged 設為 true,並確保 volumes 包含 /var/run/docker.sock

WARNING

network_mode 不可設定為 host,否則可能導致 GitLab 服務忙碌無法回應。

GitLab CI 實例 (.NET 6)

透過 .gitlab-ci.yml 定義 Build、List、Deploy 三個階段。

yaml
stages:
  - build
  - list
  - deploy

build-job:
  stage: build
  image: mcr.microsoft.com/dotnet/sdk:6.0
  tags: ['docker', 'linux']
  script:
    - cd src/TestCore
    - dotnet restore
    - dotnet build --configuration Release
    - dotnet publish --configuration Release --output ../../build/publish
  artifacts:
    paths:
      - ./build/publish/*

deploy-job:
  stage: deploy
  tags: ['docker', 'linux']
  script:
    - cd build
    - docker build --tag $CI_PROJECT_PATH_SLUG:latest .
    - docker stop $CI_PROJECT_NAME || true && docker rm $CI_PROJECT_NAME || true
    - docker run -d -p 9080:80 --name $CI_PROJECT_NAME $CI_PROJECT_PATH_SLUG:latest

關鍵技術分析

  • Artifacts 傳遞:由於每個 Stage 都是獨立的 Container,必須透過 artifacts 將編譯後的檔案從 build-job 傳遞至 deploy-job
  • Docker-outside-of-Docker:透過掛載 docker.sock,讓 Runner 能夠直接呼叫宿主機的 Docker Engine 來建置與執行容器,此方式比 DIND 更穩定且易於管理。
  • 環境變數:使用 $CI_PROJECT_PATH_SLUG 處理專案名稱,因為 Docker Image 名稱不支援大寫字母。

![gitlab artifact download interface](../images/如何在 Docker 使用 GitLab CI/gitlab-artifact-download-ui.png)

![gitlab environment interface](../images/如何在 Docker 使用 GitLab CI/gitlab-environment-ui.png)

異動歷程

  • 2022-10-24 初版文件建立。